package io.kiki.stack.http.feign.form.feign.spring;

import lombok.val;
import org.apache.commons.text.StringEscapeUtils;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.HtmlUtils;

import java.io.IOException;
import java.util.Map;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.springframework.http.HttpStatus.I_AM_A_TEAPOT;
import static org.springframework.http.HttpStatus.OK;
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;

@RestController
@EnableFeignClients
@SpringBootApplication
@SuppressWarnings("checkstyle:DesignForExtension")
public class Server {

    @PostMapping(path = "/multipart/upload1/{folder}", consumes = MULTIPART_FORM_DATA_VALUE)
    public String upload1(@PathVariable("folder") String folder, @RequestPart("file") MultipartFile file, @RequestParam(value = "message", required = false) String message) throws IOException {
        return new String(file.getBytes()) + ':' + message + ':' + folder;
    }

    @PostMapping(path = "/multipart/upload2/{folder}", consumes = MULTIPART_FORM_DATA_VALUE)
    public String upload2(@RequestBody MultipartFile file, @PathVariable("folder") String folder, @RequestParam(value = "message", required = false) String message) throws IOException {
        return new String(file.getBytes()) + ':' + message + ':' + folder;
    }

    @PostMapping(path = "/multipart/upload3/{folder}", consumes = MULTIPART_FORM_DATA_VALUE)
    public String upload3(@RequestBody MultipartFile file, @PathVariable("folder") String folder, @RequestParam(value = "message", required = false) String message) {
        return file.getOriginalFilename() + ':' + file.getContentType() + ':' + folder;
    }

    @PostMapping("/multipart/upload4/{id}")
    public String upload4(@PathVariable("id") String id, @RequestBody Map<String, Object> map, @RequestParam String userName) {
        return HtmlUtils.htmlEscape(userName) + ':' + HtmlUtils.htmlEscape(id) + ':' + map.size();
    }

    @PostMapping(path = "/multipart/upload5", consumes = MULTIPART_FORM_DATA_VALUE)
    void upload5(Dto dto) throws IOException {
        assert "field 1 value".equals(dto.getField1());
        assert 42 == dto.getField2();

        assert "Hello world".equals(new String(dto.getFile().getBytes(), UTF_8));
    }

    @PostMapping(path = "/multipart/upload6", consumes = MULTIPART_FORM_DATA_VALUE)
    public ResponseEntity<String> upload6(@RequestParam("popa1") MultipartFile popa1, @RequestParam("popa2") MultipartFile popa2) throws Exception {
        HttpStatus status = I_AM_A_TEAPOT;
        String result = "";
        if (popa1 != null && popa2 != null) {
            status = OK;
            result = StringEscapeUtils.escapeHtml4(new String(popa1.getBytes())) + StringEscapeUtils.escapeHtml4(new String(popa2.getBytes()));
        }
        return ResponseEntity.status(status).body(result);
    }

    @GetMapping(path = "/multipart/download/{fileId}", produces = MULTIPART_FORM_DATA_VALUE)
    public MultiValueMap<String, Object> download(@PathVariable("fileId") String fileId) {
        val multiParts = new LinkedMultiValueMap<String, Object>();

        val infoString = "The text for file ID " + fileId + ". Testing unicode €";
        val infoPartheader = new HttpHeaders();
        infoPartheader.setContentType(new MediaType("text", "plain", UTF_8));

        val infoPart = new HttpEntity<String>(infoString, infoPartheader);

        val file = new ClassPathResource("testfile.txt");
        val filePartheader = new HttpHeaders();
        filePartheader.setContentType(APPLICATION_OCTET_STREAM);
        val filePart = new HttpEntity<ClassPathResource>(file, filePartheader);

        multiParts.add("info", infoPart);
        multiParts.add("file", filePart);
        return multiParts;
    }
}
